home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / telnet.c < prev    next >
C/C++ Source or Header  |  2001-06-30  |  59KB  |  2,722 lines

  1. /*
  2.  * Modifications Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  * Original X11 Port Copyright 1990 by Jeff Sparkes.
  4.  *  Permission to use, copy, modify, and distribute this software and its
  5.  *  documentation for any purpose and without fee is hereby granted,
  6.  *  provided that the above copyright notice appear in all copies and that
  7.  *  both that copyright notice and this permission notice appear in
  8.  *  supporting documentation.
  9.  *
  10.  * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
  11.  *  All Rights Reserved.  GTRC hereby grants public use of this software.
  12.  *  Derivative works based on this software must incorporate this copyright
  13.  *  notice.
  14.  */
  15.  
  16. /*
  17.  *    telnet.c
  18.  *        This module initializes and manages a telnet socket to
  19.  *        the given IBM host.
  20.  */
  21.  
  22. #ifdef AMIGA
  23. /*use defines for AmiTCP*/
  24. #include <sys/errno.h>
  25. #endif
  26.  
  27. #include "globals.h"
  28. #include <sys/socket.h>
  29. #include <sys/ioctl.h>
  30. #include <netinet/in.h>
  31. #define TELCMDS 1
  32. #define TELOPTS 1
  33. #include "arpa_telnet.h"
  34. #include <arpa/inet.h>
  35. #ifndef AMIGA
  36. #include <errno.h>
  37. #endif
  38. #include <fcntl.h>
  39. #include <netdb.h>
  40. #include <stdarg.h>
  41. #include "tn3270e.h"
  42.  
  43. #include "appres.h"
  44.  
  45. #include "ansic.h"
  46. #include "ctlrc.h"
  47. #include "hostc.h"
  48. #include "kybdc.h"
  49. #include "macrosc.h"
  50. #include "popupsc.h"
  51. #include "statusc.h"
  52. #include "telnetc.h"
  53. #include "trace_dsc.h"
  54. #include "utilc.h"
  55. #include "xioc.h"
  56.  
  57. #if !defined(TELOPT_NAWS) /*[*/
  58. #define TELOPT_NAWS    31
  59. #endif /*]*/
  60.  
  61. #define BUFSZ        4096
  62. #define TRACELINE    72
  63.  
  64. #define N_OPTS        256
  65.  
  66. /* Globals */
  67. char        *hostname = CN;
  68. time_t          ns_time;
  69. int             ns_brcvd;
  70. int             ns_rrcvd;
  71. int             ns_bsent;
  72. int             ns_rsent;
  73. unsigned char  *obuf;        /* 3270 output buffer */
  74. unsigned char  *obptr = (unsigned char *) NULL;
  75. int             linemode = 1;
  76. #if defined(LOCAL_PROCESS) /*[*/
  77. Boolean        local_process = False;
  78. #endif /*]*/
  79. char           *termtype;
  80.  
  81. /* Externals */
  82. extern struct timeval ds_ts;
  83.  
  84. #ifdef AMIGA
  85. void fcntl(int a,int b,int c)
  86. {
  87. }
  88.  
  89. #undef errno
  90. /*use AmiTCP's errno*/
  91. #define errno Errno()
  92.  
  93. #define close(x) CloseSocket(x)
  94. #endif
  95.  
  96.  
  97. /* Statics */
  98. static int      sock = -1;    /* active socket */
  99. static unsigned char myopts[N_OPTS], hisopts[N_OPTS];
  100.             /* telnet option flags */
  101. static unsigned char *ibuf = (unsigned char *) NULL;
  102.             /* 3270 input buffer */
  103. static unsigned char *ibptr;
  104. static int      ibuf_size = 0;    /* size of ibuf */
  105. static unsigned char *obuf_base = (unsigned char *)NULL;
  106. static int    obuf_size = 0;
  107. static unsigned char *netrbuf = (unsigned char *)NULL;
  108.             /* network input buffer */
  109. static unsigned char *sbbuf = (unsigned char *)NULL;
  110.             /* telnet sub-option buffer */
  111. static unsigned char *sbptr;
  112. static unsigned char telnet_state;
  113. static int      syncing;
  114. static char     ttype_tmpval[13];
  115.  
  116. #if defined(X3270_TN3270E) /*[*/
  117. static unsigned long e_funcs;    /* negotiated TN3270E functions */
  118. #define E_OPT(n)    (1 << (n))
  119. static unsigned short e_xmit_seq; /* transmit sequence number */
  120. static int response_required;
  121. #endif /*]*/
  122.  
  123. #if defined(X3270_ANSI) /*[*/
  124. static int      ansi_data = 0;
  125. static unsigned char *lbuf = (unsigned char *)NULL;
  126.             /* line-mode input buffer */
  127. static unsigned char *lbptr;
  128. static int      lnext = 0;
  129. static int      backslashed = 0;
  130. static int      t_valid = 0;
  131. static char     vintr;
  132. static char     vquit;
  133. static char     verase;
  134. static char     vkill;
  135. static char     veof;
  136. static char     vwerase;
  137. static char     vrprnt;
  138. static char     vlnext;
  139. #endif /*]*/
  140.  
  141. static int    tn3270e_negotiated = 0;
  142. static enum { E_NONE, E_3270, E_NVT, E_SSCP } tn3270e_submode = E_NONE;
  143. static int    tn3270e_bound = 0;
  144. static char    **lus = (char **)NULL;
  145. static char    **curr_lu = (char **)NULL;
  146. static char    *try_lu = CN;
  147.  
  148. static int telnet_fsm(unsigned char c);
  149. static void net_rawout(unsigned const char *buf, int len);
  150. static void check_in3270(void);
  151. static void store3270in(unsigned char c);
  152. static void check_linemode(Boolean init);
  153. static int non_blocking(Boolean on);
  154. static void net_connected(void);
  155. #if defined(X3270_TN3270E) /*[*/
  156. static int tn3270e_negotiate(void);
  157. #endif /*]*/
  158. static int process_eor(void);
  159. #if defined(X3270_TN3270E) /*[*/
  160. static const char *tn3270e_function_names(const unsigned char *, int);
  161. static void tn3270e_subneg_send(unsigned char, unsigned long);
  162. static unsigned long tn3270e_fdecode(const unsigned char *, int);
  163. static void tn3270e_ack(void);
  164. static void tn3270e_nak(enum pds);
  165. #endif /*]*/
  166.  
  167. #if defined(X3270_ANSI) /*[*/
  168. static void do_data(char c);
  169. static void do_intr(char c);
  170. static void do_quit(char c);
  171. static void do_cerase(char c);
  172. static void do_werase(char c);
  173. static void do_kill(char c);
  174. static void do_rprnt(char c);
  175. static void do_eof(char c);
  176. static void do_eol(char c);
  177. static void do_lnext(char c);
  178. static char parse_ctlchar(char *s);
  179. static void cooked_init(void);
  180. #endif /*]*/
  181.  
  182. #if defined(X3270_TRACE) /*[*/
  183. static void trace_str(const char *s);
  184. static void vtrace_str(const char *fmt, ...);
  185. static const char *cmd(unsigned char c);
  186. static const char *opt(unsigned char c);
  187. static const char *nnn(int c);
  188. #else /*][*/
  189. #define trace_str 0 &&
  190. #define vtrace_str 0 &&
  191. #define cmd(x) 0
  192. #define opt(x) 0
  193. #define nnn(x) 0
  194. #endif /*]*/
  195.  
  196. /* telnet states */
  197. #define TNS_DATA    0    /* receiving data */
  198. #define TNS_IAC        1    /* got an IAC */
  199. #define TNS_WILL    2    /* got an IAC WILL */
  200. #define TNS_WONT    3    /* got an IAC WONT */
  201. #define TNS_DO        4    /* got an IAC DO */
  202. #define TNS_DONT    5    /* got an IAC DONT */
  203. #define TNS_SB        6    /* got an IAC SB */
  204. #define TNS_SB_IAC    7    /* got an IAC after an IAC SB */
  205.  
  206. /* telnet predefined messages */
  207. static unsigned char    do_opt[]    = { 
  208.     IAC, DO, '_' };
  209. static unsigned char    dont_opt[]    = { 
  210.     IAC, DONT, '_' };
  211. static unsigned char    will_opt[]    = { 
  212.     IAC, WILL, '_' };
  213. static unsigned char    wont_opt[]    = { 
  214.     IAC, WONT, '_' };
  215. #if defined(X3270_TN3270E) /*[*/
  216. static unsigned char    functions_req[] = {
  217.     IAC, SB, TELOPT_TN3270E, TN3270E_OP_FUNCTIONS };
  218. #endif /*]*/
  219.  
  220. static const char *telquals[2] = { "IS", "SEND" };
  221. #if defined(X3270_TN3270E) /*[*/
  222. static const char *reason_code[8] = { "CONN-PARTNER", "DEVICE-IN-USE",
  223.     "INV-ASSOCIATE", "INV-NAME", "INV-DEVICE-TYPE", "TYPE-NAME-ERROR",
  224.     "UNKNOWN-ERROR", "UNSUPPORTED-REQ" };
  225. #define rsn(n)    (((n) <= TN3270E_REASON_UNSUPPORTED_REQ) ? \
  226.             reason_code[(n)] : "??")
  227. static const char *function_name[5] = { "BIND-IMAGE", "DATA-STREAM-CTL",
  228.     "RESPONSES", "SCS-CTL-CODES", "SYSREQ" };
  229. #define fnn(n)    (((n) <= TN3270E_FUNC_SYSREQ) ? \
  230.             function_name[(n)] : "??")
  231. static const char *data_type[9] = { "3270-DATA", "SCS-DATA", "RESPONSE",
  232.     "BIND-IMAGE", "UNBIND", "NVT-DATA", "REQUEST", "SSCP-LU-DATA",
  233.     "PRINT-EOJ" };
  234. #define e_dt(n)    (((n) <= TN3270E_DT_PRINT_EOJ) ? \
  235.             data_type[(n)] : "??")
  236. static const char *req_flag[1] = { " ERR-COND-CLEARED" };
  237. #define e_rq(fn, n) (((fn) == TN3270E_DT_REQUEST) ? \
  238.             (((n) <= TN3270E_RQF_ERR_COND_CLEARED) ? \
  239.             req_flag[(n)] : " ??") : "")
  240. static const char *hrsp_flag[3] = { "NO-RESPONSE", "ERROR-RESPONSE",
  241.     "ALWAYS-RESPONSE" };
  242. #define e_hrsp(n) (((n) <= TN3270E_RSF_ALWAYS_RESPONSE) ? \
  243.             hrsp_flag[(n)] : "??")
  244. static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" };
  245. #define e_trsp(n) (((n) <= TN3270E_RSF_NEGATIVE_RESPONSE) ? \
  246.             trsp_flag[(n)] : "??")
  247. #define e_rsp(fn, n) (((fn) == TN3270E_DT_RESPONSE) ? e_trsp(n) : e_hrsp(n))
  248. #endif /*]*/
  249.  
  250.  
  251. /*
  252.  * net_connect
  253.  *    Establish a telnet socket to the given host passed as an argument.
  254.  *    Called only once and is responsible for setting up the telnet
  255.  *    variables.  Returns the file descriptor of the connected socket.
  256.  */
  257. int
  258. net_connect(const char *host, char *portname, Boolean ls, Boolean *pending)
  259. {
  260.     struct servent    *sp;
  261.     struct hostent    *hp;
  262.     unsigned short        port;
  263.     char                passthru_haddr[8];
  264.     int            passthru_len = 0;
  265.     unsigned short        passthru_port = 0;
  266.     struct sockaddr_in    haddr;
  267.     int            on = 1;
  268. #if defined(OMTU) /*[*/
  269.     int            mtu = OMTU;
  270. #endif /*]*/
  271.  
  272. #    define close_fail    { (void) close(sock); sock = -1; return -1; }
  273.  
  274.     if (netrbuf == (unsigned char *)NULL)
  275.         netrbuf = (unsigned char *)Malloc(BUFSZ);
  276.  
  277. #if defined(X3270_ANSI) /*[*/
  278.     if (!t_valid) {
  279.         vintr   = parse_ctlchar(appres.intr);
  280.         vquit   = parse_ctlchar(appres.quit);
  281.         verase  = parse_ctlchar(appres.erase);
  282.         vkill   = parse_ctlchar(appres.kill);
  283.         veof    = parse_ctlchar(appres.eof);
  284.         vwerase = parse_ctlchar(appres.werase);
  285.         vrprnt  = parse_ctlchar(appres.rprnt);
  286.         vlnext  = parse_ctlchar(appres.lnext);
  287.         t_valid = 1;
  288.     }
  289. #endif /*]*/
  290.  
  291.     *pending = False;
  292.  
  293.     if (hostname)
  294.         Free(hostname);
  295.     hostname = NewString(host);
  296.  
  297.     /* get the passthru host and port number */
  298.     if (passthru_host) {
  299.         const char *hn;
  300.  
  301.         hn = getenv("INTERNET_HOST");
  302.         if (hn == CN)
  303.             hn = "internet-gateway";
  304.  
  305.         hp = gethostbyname(hn);
  306.         if (hp == (struct hostent *) 0) {
  307.             popup_an_error("Unknown passthru host: %s", hn);
  308.             return -1;
  309.         }
  310.         (void) memmove(passthru_haddr, hp->h_addr, hp->h_length);
  311.         passthru_len = hp->h_length;
  312.  
  313.         sp = getservbyname("telnet-passthru","tcp");
  314.         if (sp != (struct servent *)NULL)
  315.             passthru_port = sp->s_port;
  316.         else
  317.             passthru_port = htons(3514);
  318.     }
  319.  
  320.     /* get the port number */
  321.     port = (unsigned short) atoi(portname);
  322.     if (port)
  323.         port = htons(port);
  324.     else {
  325.         if (!(sp = getservbyname(portname, "tcp"))) {
  326.             popup_an_error("Unknown port number or service: %s",
  327.                 portname);
  328.             return -1;
  329.         }
  330.         port = sp->s_port;
  331.     }
  332.     current_port = ntohs(port);
  333.  
  334.  
  335.     /* fill in the socket address of the given host */
  336.     (void) memset((char *) &haddr, 0, sizeof(haddr));
  337.     if (passthru_host) {
  338.         haddr.sin_family = AF_INET;
  339.         (void) memmove(&haddr.sin_addr, passthru_haddr, passthru_len);
  340.         haddr.sin_port = passthru_port;
  341.     } else {
  342. #if defined(LOCAL_PROCESS) /*[*/
  343.         if (ls) {
  344.             local_process = True;
  345.         } else {
  346.             local_process = False;
  347. #endif /*]*/
  348.             hp = gethostbyname(host);
  349.             if (hp == (struct hostent *) 0) {
  350.                 haddr.sin_family = AF_INET;
  351.                 haddr.sin_addr.s_addr = inet_addr(host);
  352.                 if (haddr.sin_addr.s_addr == (unsigned long)-1) {
  353.                     popup_an_error("Unknown host:\n%s",
  354.                         hostname);
  355.                     return -1;
  356.                 }
  357.             }
  358.             else {
  359.                 haddr.sin_family = hp->h_addrtype;
  360.                 (void) memmove(&haddr.sin_addr, hp->h_addr,
  361.                            hp->h_length);
  362.             }
  363.             haddr.sin_port = port;
  364. #if defined(LOCAL_PROCESS) /*[*/
  365.         }
  366. #endif /*]*/
  367.  
  368.     }
  369.  
  370. #if defined(LOCAL_PROCESS) /*[*/
  371.     if (local_process) {
  372.         int amaster;
  373.         struct winsize w;
  374.  
  375.         w.ws_row = maxROWS;
  376.         w.ws_col = maxCOLS;
  377.         w.ws_xpixel = 0;
  378.         w.ws_ypixel = 0;
  379.  
  380.         switch (forkpty(&amaster, NULL, NULL, &w)) {
  381.             case -1:    /* failed */
  382.             popup_an_errno(errno, "forkpty");
  383.             close_fail;
  384.             case 0:    /* child */
  385.             putenv("TERM=xterm");
  386.             if (strchr(host, ' ') != CN) {
  387.                 (void) execlp("/bin/sh", "sh", "-c", host,
  388.                     NULL);
  389.             } else {
  390.                 char *arg1;
  391.  
  392.                 arg1 = strrchr(host, '/');
  393.                 (void) execlp(host,
  394.                     (arg1 == CN) ? host : arg1 + 1,
  395.                     NULL);
  396.             }
  397.             perror(host);
  398.             _exit(1);
  399.             break;
  400.             default:    /* parent */
  401.             sock = amaster;
  402.  
  403.             (void) fcntl(sock, F_SETFD, 1);
  404.             net_connected();
  405.             host_in3270(CONNECTED_ANSI);
  406.             break;
  407.         }
  408.     } else {
  409. #endif /*]*/
  410.         /* create the socket */
  411.         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  412.             popup_an_errno(errno, "socket");
  413.             return -1;
  414.         }
  415.  
  416.         /* set options for inline out-of-band data and keepalives */
  417.         if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
  418.                 sizeof(on)) < 0) {
  419.             popup_an_errno(errno, "setsockopt(SO_OOBINLINE)");
  420.             close_fail;
  421.         }
  422.         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  423.                 sizeof(on)) < 0) {
  424.             popup_an_errno(errno, "setsockopt(SO_KEEPALIVE)");
  425.             close_fail;
  426.         }
  427. #if defined(OMTU) /*[*/
  428.         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&mtu,
  429.                 sizeof(mtu)) < 0) {
  430.             popup_an_errno(errno, "setsockopt(SO_SNDBUF)");
  431.             close_fail;
  432.         }
  433. #endif /*]*/
  434.  
  435.         /* set the socket to be non-delaying */
  436.         if (non_blocking(True) < 0)
  437.             close_fail;
  438.  
  439.         /* don't share the socket with our children */
  440.         (void) fcntl(sock, F_SETFD, 1);
  441.  
  442.         /* connect */
  443.         if (connect(sock, (struct sockaddr *) &haddr, sizeof(haddr)) == -1) {
  444.             if (errno == EWOULDBLOCK
  445. #if defined(EINPROGRESS) /*[*/
  446.                 || errno == EINPROGRESS
  447. #endif /*]*/
  448.                            ) {
  449.                 trace_str("Connection pending.\n");
  450.                 *pending = True;
  451.             } else {
  452.                 popup_an_errno(errno, "Connect to %s, port %d",
  453.                     hostname, current_port);
  454.                 close_fail;
  455.             }
  456.         } else {
  457.             if (non_blocking(False) < 0)
  458.                 close_fail;
  459.             net_connected();
  460.         }
  461. #if defined(LOCAL_PROCESS) /*[*/
  462.     }
  463. #endif /*]*/
  464.  
  465.     /* set up temporary termtype */
  466.     if (appres.termname == CN && std_ds_host) {
  467.         (void) sprintf(ttype_tmpval, "IBM-327%c-%d",
  468.             appres.m3279 ? '9' : '8', model_num);
  469.         termtype = ttype_tmpval;
  470.     }
  471.  
  472.     /* all done */
  473.     return sock;
  474. }
  475. #undef close_fail
  476.  
  477. /* Set up the LU list. */
  478. static void
  479. setup_lus(void)
  480. {
  481.     char *lu;
  482.     char *comma;
  483.     int n_lus = 1;
  484.     int i;
  485.  
  486.     connected_lu = CN;
  487.     connected_type = CN;
  488.  
  489.     if (!luname[0]) {
  490.         if (lus) {
  491.             Free(lus);
  492.             lus = (char **)NULL;
  493.         }
  494.         curr_lu = (char **)NULL;
  495.         try_lu = CN;
  496.         return;
  497.     }
  498.  
  499.     /*
  500.      * Count the commas in the LU name.  That plus one is the
  501.      * number of LUs to try. 
  502.      */
  503.     lu = luname;
  504.     while ((comma = strchr(lu, ',')) != CN) {
  505.         n_lus++;
  506.         lu++;
  507.     }
  508.  
  509.     /*
  510.      * Allocate enough memory to construct an argv[] array for
  511.      * the LUs.
  512.      */
  513.     lus = (char **)Malloc((n_lus+1) * sizeof(char *) + strlen(luname) + 1);
  514.  
  515.     /* Copy each LU into the array. */
  516.     lu = (char *)(lus + n_lus + 1);
  517.     (void) strcpy(lu, luname);
  518.     i = 0;
  519.     do {
  520.         lus[i++] = lu;
  521.         comma = strchr(lu, ',');
  522.         if (comma != CN) {
  523.             *comma = '\0';
  524.             lu = comma + 1;
  525.         }
  526.     } while (comma != CN);
  527.     lus[i] = CN;
  528.     curr_lu = lus;
  529.     try_lu = *curr_lu;
  530. }
  531.  
  532. static void
  533. net_connected(void)
  534. {
  535.     vtrace_str("Connected to %s, port %u.\n", hostname, current_port);
  536.  
  537.     /* set up telnet options */
  538.     (void) memset((char *) myopts, 0, sizeof(myopts));
  539.     (void) memset((char *) hisopts, 0, sizeof(hisopts));
  540. #if defined(X3270_TN3270E) /*[*/
  541.     e_funcs = E_OPT(TN3270E_FUNC_BIND_IMAGE) |
  542.           E_OPT(TN3270E_FUNC_RESPONSES) |
  543.           E_OPT(TN3270E_FUNC_SYSREQ);
  544.     e_xmit_seq = 0;
  545.     response_required = TN3270E_RSF_NO_RESPONSE;
  546. #endif /*]*/
  547.     telnet_state = TNS_DATA;
  548.     ibptr = ibuf;
  549.  
  550.     /* clear statistics and flags */
  551.     (void) time(&ns_time);
  552.     ns_brcvd = 0;
  553.     ns_rrcvd = 0;
  554.     ns_bsent = 0;
  555.     ns_rsent = 0;
  556.     syncing = 0;
  557.     tn3270e_negotiated = 0;
  558.     tn3270e_submode = E_NONE;
  559.     tn3270e_bound = 0;
  560.  
  561.     setup_lus();
  562.  
  563.     check_linemode(True);
  564.  
  565.     /* write out the passthru hostname and port nubmer */
  566.     if (passthru_host) {
  567.         char *buf;
  568.  
  569.         buf = Malloc(strlen(hostname) + 32);
  570.         (void) sprintf(buf, "%s %d\r\n", hostname, current_port);
  571.         (void) write(sock, buf, strlen(buf));
  572.         Free(buf);
  573.     }
  574. }
  575.  
  576. /*
  577.  * net_disconnect
  578.  *    Shut down the socket.
  579.  */
  580. void
  581. net_disconnect(void)
  582. {
  583.     if (CONNECTED)
  584.         (void) shutdown(sock, 2);
  585.     (void) close(sock);
  586.     sock = -1;
  587.     trace_str("SENT disconnect\n");
  588.  
  589.     /* Restore terminal type to its default. */
  590.     if (appres.termname == CN)
  591.         termtype = full_model_name;
  592. }
  593.  
  594.  
  595. /*
  596.  * net_input
  597.  *    Called by the toolkit whenever there is input available on the
  598.  *    socket.  Reads the data, processes the special telnet commands
  599.  *    and calls process_ds to process the 3270 data stream.
  600.  */
  601. #ifdef AMIGA
  602. static int telnet_readstat=0;
  603.  
  604. int telnet_getreadstat(void)
  605. {
  606. return(telnet_readstat);
  607. }
  608. #endif
  609.  
  610. void
  611. net_input(void)
  612. {
  613.     register unsigned char    *cp;
  614.     int    nr;
  615.  
  616.         telnet_readstat=1;
  617.  
  618. #if defined(X3270_ANSI) /*[*/
  619.     ansi_data = 0;
  620. #endif /*]*/
  621.  
  622.     nr = read(sock, (char *) netrbuf, BUFSZ);
  623.     if (nr < 0) {
  624. #ifdef AMIGA
  625.         if (errno == EAGAIN)
  626.                         {telnet_readstat=0;
  627.             return;}
  628. #endif
  629.         if (errno == EWOULDBLOCK)
  630.                         {telnet_readstat=0;
  631.             return;}
  632.         if (HALF_CONNECTED && errno == EAGAIN) {
  633.             if (non_blocking(False) < 0) {
  634.                 host_disconnect(True);
  635.                                 {telnet_readstat=0;
  636.                 return;}
  637.             }
  638.             host_connected();
  639.             net_connected();
  640.                         {telnet_readstat=0;
  641.             return;}
  642.         }
  643.         vtrace_str("RCVD socket error %d\n", errno);
  644.         if (HALF_CONNECTED)
  645.             popup_an_errno(errno, "Connect to %s, port %d",
  646.                 hostname, current_port);
  647.         else if (errno != ECONNRESET)
  648.             popup_an_errno(errno, "Socket read");
  649.         host_disconnect(True);
  650.                 {telnet_readstat=0;
  651.         return;}
  652.     } else if (nr == 0) {
  653.         /* Host disconnected. */
  654.         trace_str("RCVD disconnect\n");
  655.         host_disconnect(False);
  656.                 {telnet_readstat=0;
  657.         return;}
  658.     }
  659.  
  660.     /* Process the data. */
  661.  
  662.     if (HALF_CONNECTED) {
  663.         if (non_blocking(False) < 0) {
  664.             host_disconnect(True);
  665.                         {telnet_readstat=0;
  666.             return;}
  667.         }
  668.         host_connected();
  669.         net_connected();
  670.     }
  671.  
  672. #if defined(X3270_TRACE) /*[*/
  673.     trace_netdata('<', netrbuf, nr);
  674. #endif /*]*/
  675.  
  676.     ns_brcvd += nr;
  677.     for (cp = netrbuf; cp < (netrbuf + nr); cp++) {
  678. #if defined(LOCAL_PROCESS) /*[*/
  679.         if (local_process) {
  680.             /* More to do here, probably. */
  681.             if (IN_NEITHER) {    /* now can assume ANSI mode */
  682.                 host_in3270(CONNECTED_ANSI);
  683.                 hisopts[TELOPT_ECHO] = 1;
  684.                 check_linemode(False);
  685.                 kybdlock_clr(KL_AWAITING_FIRST, "telnet_fsm");
  686.                 status_reset();
  687.                 ps_process();
  688.             }
  689.             ansi_process((unsigned int) *cp);
  690.         } else {
  691. #endif /*]*/
  692.             if (telnet_fsm(*cp)) {
  693.                 host_disconnect(True);
  694.                                 {telnet_readstat=0;
  695.                 return;}
  696.             }
  697. #if defined(LOCAL_PROCESS) /*[*/
  698.         }
  699. #endif /*]*/
  700.     }
  701.  
  702. #if defined(X3270_ANSI) /*[*/
  703.     if (ansi_data) {
  704.         trace_str("\n");
  705.         ansi_data = 0;
  706.     }
  707. #endif /*]*/
  708.    telnet_readstat=0;
  709.    return;
  710. }
  711.  
  712.  
  713. /*
  714.  * set16
  715.  *    Put a 16-bit value in a buffer.
  716.  *    Returns the number of bytes required.
  717.  */
  718. static int
  719. set16(char *buf, int n)
  720. {
  721.     char *b0 = buf;
  722.  
  723.     n %= 256 * 256;
  724.     if ((n / 256) == IAC)
  725.         *(unsigned char *)buf++ = IAC;
  726.     *buf++ = (n / 256);
  727.     n %= 256;
  728.     if (n == IAC)
  729.         *(unsigned char *)buf++ = IAC;
  730.     *buf++ = n;
  731.     return buf - b0;
  732. }
  733.  
  734. /*
  735.  * send_naws
  736.  *    Send a Telnet window size sub-option negotation.
  737.  */
  738. static void
  739. send_naws(void)
  740. {
  741.     char naws_msg[14];
  742.     int naws_len = 0;
  743.  
  744.     (void) sprintf(naws_msg, "%c%c%c", IAC, SB, TELOPT_NAWS);
  745.     naws_len += 3;
  746.     naws_len += set16(naws_msg + naws_len, maxCOLS);
  747.     naws_len += set16(naws_msg + naws_len, maxROWS);
  748.     (void) sprintf(naws_msg + naws_len, "%c%c", IAC, SE);
  749.     naws_len += 2;
  750.     net_rawout((unsigned char *)naws_msg, naws_len);
  751.     vtrace_str("SENT %s NAWS %d %d %s\n", cmd(SB), maxCOLS,
  752.         maxROWS, cmd(SE));
  753. }
  754.  
  755.  
  756.  
  757. /* Advance 'try_lu' to the next desired LU name. */
  758. static void
  759. next_lu(void)
  760. {
  761.     if (curr_lu != (char **)NULL && (try_lu = *++curr_lu) == CN)
  762.         curr_lu = (char **)NULL;
  763. }
  764.  
  765. /*
  766.  * telnet_fsm
  767.  *    Telnet finite-state machine.
  768.  *    Returns 0 for okay, -1 for errors.
  769.  */
  770. static int
  771. telnet_fsm(unsigned char c)
  772. {
  773.     char    *see_chr;
  774.     int    sl;
  775.  
  776.     switch (telnet_state) {
  777.         case TNS_DATA:    /* normal data processing */
  778.         if (c == IAC) {    /* got a telnet command */
  779.             telnet_state = TNS_IAC;
  780. #if defined(X3270_ANSI) /*[*/
  781.             if (ansi_data) {
  782.                 trace_str("\n");
  783.                 ansi_data = 0;
  784.             }
  785. #endif /*]*/
  786.             break;
  787.         }
  788.         if (IN_NEITHER) {    /* now can assume ANSI mode */
  789.             host_in3270(CONNECTED_ANSI);
  790. #if defined(X3270_ANSI)/*[*/
  791.             if (linemode)
  792.                 cooked_init();
  793. #endif /*]*/
  794.             kybdlock_clr(KL_AWAITING_FIRST, "telnet_fsm");
  795.             status_reset();
  796.             ps_process();
  797.         }
  798.         if (IN_ANSI && !IN_E) {
  799. #if defined(X3270_ANSI) /*[*/
  800.             if (!ansi_data) {
  801.                 trace_str("<.. ");
  802.                 ansi_data = 4;
  803.             }
  804.             see_chr = ctl_see((int) c);
  805.             ansi_data += (sl = strlen(see_chr));
  806.             if (ansi_data >= TRACELINE) {
  807.                 trace_str(" ...\n... ");
  808.                 ansi_data = 4 + sl;
  809.             }
  810.             trace_str(see_chr);
  811.             if (!syncing) {
  812.                 ansi_process((unsigned int) c);
  813.                 sms_store(c);
  814.             }
  815. #endif /*]*/
  816.         } else {
  817.             store3270in(c);
  818.         }
  819.         break;
  820.         case TNS_IAC:    /* process a telnet command */
  821.         if (c != EOR && c != IAC) {
  822.             vtrace_str("RCVD %s ", cmd(c));
  823.         }
  824.         switch (c) {
  825.             case IAC:    /* escaped IAC, insert it */
  826.             if (IN_ANSI && !IN_E) {
  827. #if defined(X3270_ANSI) /*[*/
  828.                 if (!ansi_data) {
  829.                     trace_str("<.. ");
  830.                     ansi_data = 4;
  831.                 }
  832.                 see_chr = ctl_see((int) c);
  833.                 ansi_data += (sl = strlen(see_chr));
  834.                 if (ansi_data >= TRACELINE) {
  835.                     trace_str(" ...\n ...");
  836.                     ansi_data = 4 + sl;
  837.                 }
  838.                 trace_str(see_chr);
  839.                 ansi_process((unsigned int) c);
  840.                 sms_store(c);
  841. #endif /*]*/
  842.             } else
  843.                 store3270in(c);
  844.             telnet_state = TNS_DATA;
  845.             break;
  846.             case EOR:    /* eor, process accumulated input */
  847.             if (IN_3270 || (IN_E && tn3270e_negotiated)) {
  848.                 ns_rrcvd++;
  849.                 if (process_eor())
  850.                     return -1;
  851.             } else
  852.                 Warning("EOR received when not in 3270 mode, "
  853.                     "ignored.");
  854.             trace_str("RCVD EOR\n");
  855.             ibptr = ibuf;
  856.             telnet_state = TNS_DATA;
  857.             break;
  858.             case WILL:
  859.             telnet_state = TNS_WILL;
  860.             break;
  861.             case WONT:
  862.             telnet_state = TNS_WONT;
  863.             break;
  864.             case DO:
  865.             telnet_state = TNS_DO;
  866.             break;
  867.             case DONT:
  868.             telnet_state = TNS_DONT;
  869.             break;
  870.             case SB:
  871.             telnet_state = TNS_SB;
  872.             if (sbbuf == (unsigned char *)NULL)
  873.                 sbbuf = (unsigned char *)Malloc(1024);
  874.             sbptr = sbbuf;
  875.             break;
  876.             case DM:
  877.             trace_str("\n");
  878.             if (syncing) {
  879.                 syncing = 0;
  880.                 x_except_on(sock);
  881.             }
  882.             telnet_state = TNS_DATA;
  883.             break;
  884.             case GA:
  885.             case NOP:
  886.             trace_str("\n");
  887.             telnet_state = TNS_DATA;
  888.             break;
  889.             default:
  890.             trace_str("???\n");
  891.             telnet_state = TNS_DATA;
  892.             break;
  893.         }
  894.         break;
  895.         case TNS_WILL:    /* telnet WILL DO OPTION command */
  896.         vtrace_str("%s\n", opt(c));
  897.         switch (c) {
  898.             case TELOPT_SGA:
  899.             case TELOPT_BINARY:
  900.             case TELOPT_EOR:
  901.             case TELOPT_TTYPE:
  902.             case TELOPT_ECHO:
  903. #if defined(X3270_TN3270E) /*[*/
  904.             case TELOPT_TN3270E:
  905. #endif /*]*/
  906.             if (c != TELOPT_TN3270E || !non_tn3270e_host) {
  907.                 if (!hisopts[c]) {
  908.                     hisopts[c] = 1;
  909.                     do_opt[2] = c;
  910.                     net_rawout(do_opt, sizeof(do_opt));
  911.                     vtrace_str("SENT %s %s\n", cmd(DO),
  912.                         opt(c));
  913.  
  914.                     /*
  915.                      * For UTS, volunteer to do EOR when
  916.                      * they do.
  917.                      */
  918.                     if (c == TELOPT_EOR && !myopts[c]) {
  919.                         myopts[c] = 1;
  920.                         will_opt[2] = c;
  921.                         net_rawout(will_opt,
  922.                             sizeof(will_opt));
  923.                         vtrace_str("SENT %s %s\n",
  924.                             cmd(WILL), opt(c));
  925.                     }
  926.  
  927.                     check_in3270();
  928.                     check_linemode(False);
  929.                 }
  930.                 break;
  931.             }
  932.             default:
  933.             dont_opt[2] = c;
  934.             net_rawout(dont_opt, sizeof(dont_opt));
  935.             vtrace_str("SENT %s %s\n", cmd(DONT), opt(c));
  936.             break;
  937.         }
  938.         telnet_state = TNS_DATA;
  939.         break;
  940.         case TNS_WONT:    /* telnet WONT DO OPTION command */
  941.         vtrace_str("%s\n", opt(c));
  942.         if (hisopts[c]) {
  943.             hisopts[c] = 0;
  944.             dont_opt[2] = c;
  945.             net_rawout(dont_opt, sizeof(dont_opt));
  946.             vtrace_str("SENT %s %s\n", cmd(DONT), opt(c));
  947.             check_in3270();
  948.             check_linemode(False);
  949.         }
  950.         telnet_state = TNS_DATA;
  951.         break;
  952.         case TNS_DO:    /* telnet PLEASE DO OPTION command */
  953.         vtrace_str("%s\n", opt(c));
  954.         switch (c) {
  955.             case TELOPT_BINARY:
  956.             case TELOPT_EOR:
  957.             case TELOPT_TTYPE:
  958.             case TELOPT_SGA:
  959.             case TELOPT_NAWS:
  960.             case TELOPT_TM:
  961. #if defined(X3270_TN3270E) /*[*/
  962.             case TELOPT_TN3270E:
  963. #endif /*]*/
  964.             if (c != TELOPT_TN3270E || !non_tn3270e_host) {
  965.                 if (!myopts[c]) {
  966.                     if (c != TELOPT_TM)
  967.                         myopts[c] = 1;
  968.                     will_opt[2] = c;
  969.                     net_rawout(will_opt, sizeof(will_opt));
  970.                     vtrace_str("SENT %s %s\n", cmd(WILL),
  971.                         opt(c));
  972.                     check_in3270();
  973.                     check_linemode(False);
  974.                 }
  975.                 if (c == TELOPT_NAWS)
  976.                     send_naws();
  977.                 break;
  978.             }
  979.             default:
  980.             wont_opt[2] = c;
  981.             net_rawout(wont_opt, sizeof(wont_opt));
  982.             vtrace_str("SENT %s %s\n", cmd(WONT), opt(c));
  983.             break;
  984.         }
  985.         telnet_state = TNS_DATA;
  986.         break;
  987.         case TNS_DONT:    /* telnet PLEASE DON'T DO OPTION command */
  988.         vtrace_str("%s\n", opt(c));
  989.         if (myopts[c]) {
  990.             myopts[c] = 0;
  991.             wont_opt[2] = c;
  992.             net_rawout(wont_opt, sizeof(wont_opt));
  993.             vtrace_str("SENT %s %s\n", cmd(WONT), opt(c));
  994.             check_in3270();
  995.             check_linemode(False);
  996.         }
  997.         telnet_state = TNS_DATA;
  998.         break;
  999.         case TNS_SB:    /* telnet sub-option string command */
  1000.         if (c == IAC)
  1001.             telnet_state = TNS_SB_IAC;
  1002.         else
  1003.             *sbptr++ = c;
  1004.         break;
  1005.         case TNS_SB_IAC:    /* telnet sub-option string command */
  1006.         *sbptr++ = c;
  1007.         if (c == SE) {
  1008.             telnet_state = TNS_DATA;
  1009.             if (sbbuf[0] == TELOPT_TTYPE &&
  1010.                 sbbuf[1] == TELQUAL_SEND) {
  1011.                 int tt_len, tb_len;
  1012.                 char *tt_out;
  1013.  
  1014.                 vtrace_str("%s %s\n", opt(sbbuf[0]),
  1015.                     telquals[sbbuf[1]]);
  1016.                 if (lus != (char **)NULL && try_lu == CN) {
  1017.                     /* None of the LUs worked. */
  1018.                     popup_an_error("Cannot connect to "
  1019.                         "specified LU");
  1020.                     return -1;
  1021.                 }
  1022.  
  1023.                 tt_len = strlen(termtype);
  1024.                 if (try_lu != CN && *try_lu) {
  1025.                     tt_len += strlen(try_lu) + 1;
  1026.                     connected_lu = try_lu;
  1027.                 } else
  1028.                     connected_lu = CN;
  1029.  
  1030.                 tb_len = 4 + tt_len + 2;
  1031.                 tt_out = Malloc(tb_len + 1);
  1032.                 (void) sprintf(tt_out, "%c%c%c%c%s%s%s%c%c",
  1033.                     IAC, SB, TELOPT_TTYPE, TELQUAL_IS,
  1034.                     termtype,
  1035.                     (try_lu != CN && *try_lu) ? "@" : "",
  1036.                     (try_lu != CN && *try_lu) ? try_lu : "",
  1037.                     IAC, SE);
  1038.                 net_rawout((unsigned char *)tt_out, tb_len);
  1039.  
  1040.                 vtrace_str("SENT %s %s %s %.*s %s\n",
  1041.                     cmd(SB), opt(TELOPT_TTYPE),
  1042.                     telquals[TELQUAL_IS],
  1043.                     tt_len, tt_out + 4,
  1044.                     cmd(SE));
  1045.                 Free(tt_out);
  1046.  
  1047.                 /* Advance to the next LU name. */
  1048.                 next_lu();
  1049.             }
  1050. #if defined(X3270_TN3270E) /*[*/
  1051.             else if (myopts[TELOPT_TN3270E] &&
  1052.                    sbbuf[0] == TELOPT_TN3270E) {
  1053.                 if (tn3270e_negotiate())
  1054.                     return -1;
  1055.             }
  1056. #endif /*]*/
  1057.         } else {
  1058.             telnet_state = TNS_SB;
  1059.         }
  1060.         break;
  1061.     }
  1062.     return 0;
  1063. }
  1064.  
  1065. #if defined(X3270_TN3270E) /*[*/
  1066. /* Send a TN3270E terminal type request. */
  1067. static void
  1068. tn3270e_request(void)
  1069. {
  1070.     int tt_len, tb_len;
  1071.     char *tt_out;
  1072.     char *t;
  1073.  
  1074.     tt_len = strlen(termtype);
  1075.     if (try_lu != CN && *try_lu)
  1076.         tt_len += strlen(try_lu) + 1;
  1077.  
  1078.     tb_len = 5 + tt_len + 2;
  1079.     tt_out = Malloc(tb_len + 1);
  1080.     t = tt_out;
  1081.     t += sprintf(tt_out, "%c%c%c%c%c%s",
  1082.         IAC, SB, TELOPT_TN3270E, TN3270E_OP_DEVICE_TYPE,
  1083.         TN3270E_OP_REQUEST, termtype);
  1084.  
  1085.     /* Convert 3279 to 3278, per the RFC. */
  1086.     if (tt_out[12] == '9')
  1087.         tt_out[12] = '8';
  1088.  
  1089.     if (try_lu != CN && *try_lu)
  1090.         t += sprintf(t, "%c%s", TN3270E_OP_CONNECT, try_lu);
  1091.  
  1092.     (void) sprintf(t, "%c%c", IAC, SE);
  1093.  
  1094.     net_rawout((unsigned char *)tt_out, tb_len);
  1095.  
  1096.     vtrace_str("SENT %s %s DEVICE-TYPE REQUEST %.*s%s%s "
  1097.            "%s\n",
  1098.         cmd(SB), opt(TELOPT_TN3270E), strlen(termtype), tt_out + 5,
  1099.         (try_lu != CN && *try_lu) ? " CONNECT " : "",
  1100.         (try_lu != CN && *try_lu) ? try_lu : "",
  1101.         cmd(SE));
  1102.  
  1103.     Free(tt_out);
  1104. }
  1105.  
  1106. /*
  1107.  * Negotiation of TN3270E options.
  1108.  * Returns 0 if okay, -1 if we have to give up altogether.
  1109.  */
  1110. static int
  1111. tn3270e_negotiate(void)
  1112. {
  1113. #define LU_MAX    32
  1114.     static char reported_lu[LU_MAX+1];
  1115.     static char reported_type[LU_MAX+1];
  1116.     int sblen;
  1117.     unsigned long e_rcvd;
  1118.  
  1119.     /* Find out how long the subnegotiation buffer is. */
  1120.     for (sblen = 0; ; sblen++) {
  1121.         if (sbbuf[sblen] == SE)
  1122.             break;
  1123.     }
  1124.  
  1125.     vtrace_str("TN3270E ");
  1126.  
  1127.     switch (sbbuf[1]) {
  1128.  
  1129.     case TN3270E_OP_SEND:
  1130.  
  1131.         if (sbbuf[2] == TN3270E_OP_DEVICE_TYPE) {
  1132.  
  1133.             /* Host wants us to send our device type. */
  1134.             vtrace_str("SEND DEVICE-TYPE SE\n");
  1135.  
  1136.             tn3270e_request();
  1137.         } else {
  1138.             vtrace_str("SEND ??%u SE\n", sbbuf[2]);
  1139.         }
  1140.         break;
  1141.  
  1142.     case TN3270E_OP_DEVICE_TYPE:
  1143.  
  1144.         /* Device type negotiation. */
  1145.         vtrace_str("DEVICE-TYPE ");
  1146.  
  1147.         switch (sbbuf[2]) {
  1148.         case TN3270E_OP_IS: {
  1149.             int tnlen, snlen;
  1150.  
  1151.             /* Device type success. */
  1152.  
  1153.             /* Isolate the terminal type and session. */
  1154.             tnlen = 0;
  1155.             while (sbbuf[3+tnlen] != SE &&
  1156.                    sbbuf[3+tnlen] != TN3270E_OP_CONNECT)
  1157.                 tnlen++;
  1158.             snlen = 0;
  1159.             if (sbbuf[3+tnlen] == TN3270E_OP_CONNECT) {
  1160.                 while(sbbuf[3+tnlen+1+snlen] != SE)
  1161.                     snlen++;
  1162.             }
  1163.             vtrace_str("IS %.*s CONNECT %.*s SE\n",
  1164.                 tnlen, &sbbuf[3],
  1165.                 snlen, &sbbuf[3+tnlen+1]);
  1166.  
  1167.             /* Remember the LU. */
  1168.             if (tnlen) {
  1169.                 if (tnlen > LU_MAX)
  1170.                     tnlen = LU_MAX;
  1171.                 (void)strncpy(reported_type,
  1172.                     (char *)&sbbuf[3], tnlen);
  1173.                 reported_type[tnlen] = '\0';
  1174.                 connected_type = reported_type;
  1175.             }
  1176.             if (snlen) {
  1177.                 if (snlen > LU_MAX)
  1178.                     snlen = LU_MAX;
  1179.                 (void)strncpy(reported_lu,
  1180.                     (char *)&sbbuf[3+tnlen+1], snlen);
  1181.                 reported_lu[snlen] = '\0';
  1182.                 connected_lu = reported_lu;
  1183.             }
  1184.  
  1185.             /* Tell them what we can do. */
  1186.             tn3270e_subneg_send(TN3270E_OP_REQUEST, e_funcs);
  1187.             break;
  1188.         }
  1189.         case TN3270E_OP_REJECT:
  1190.  
  1191.             /* Device type failure. */
  1192.  
  1193.             vtrace_str("REJECT REASON %s SE\n", rsn(sbbuf[4]));
  1194.  
  1195.             next_lu();
  1196.             if (try_lu != CN) {
  1197.                 /* Try the next LU. */
  1198.                 tn3270e_request();
  1199.             } else if (lus != (char **)NULL) {
  1200.                 /* No more LUs to try.  Give up. */
  1201.                 popup_an_error("Cannot connect to "
  1202.                     "specified LU:\n%s", rsn(sbbuf[4]));
  1203.                 return -1;
  1204.             } else {
  1205.                 popup_an_error("Device type rejected:\n"
  1206.                     "%s", rsn(sbbuf[4]));
  1207.                 return -1;
  1208.             }
  1209.  
  1210.             break;
  1211.         default:
  1212.             vtrace_str("??%u SE\n", sbbuf[2]);
  1213.             break;
  1214.         }
  1215.         break;
  1216.  
  1217.     case TN3270E_OP_FUNCTIONS:
  1218.  
  1219.         /* Functions negotiation. */
  1220.         vtrace_str("FUNCTIONS ");
  1221.  
  1222.         switch (sbbuf[2]) {
  1223.  
  1224.         case TN3270E_OP_REQUEST:
  1225.  
  1226.             /* Host is telling us what functions they want. */
  1227.             vtrace_str("REQUEST %s SE\n",
  1228.                 tn3270e_function_names(sbbuf+3, sblen-3));
  1229.  
  1230.             e_rcvd = tn3270e_fdecode(sbbuf+3, sblen-3);
  1231.             if ((e_rcvd == e_funcs) || (e_funcs & ~e_rcvd)) {
  1232.                 /* They want what we want, or less.  Done. */
  1233.                 e_funcs = e_rcvd;
  1234.                 tn3270e_subneg_send(TN3270E_OP_IS, e_funcs);
  1235.                 tn3270e_negotiated = 1;
  1236.                 vtrace_str("TN3270E option negotiation "
  1237.                     "complete.\n");
  1238.                 check_in3270();
  1239.             } else {
  1240.                 /*
  1241.                  * They want us to do something we can't.
  1242.                  * Request the common subset.
  1243.                  */
  1244.                 e_funcs &= e_rcvd;
  1245.                 tn3270e_subneg_send(TN3270E_OP_REQUEST,
  1246.                     e_funcs);
  1247.             }
  1248.             break;
  1249.  
  1250.         case TN3270E_OP_IS:
  1251.  
  1252.             /* They accept our last request, or a subset thereof. */
  1253.             vtrace_str("IS %s SE\n",
  1254.                 tn3270e_function_names(sbbuf+3, sblen-3));
  1255.             e_rcvd = tn3270e_fdecode(sbbuf+3, sblen-3);
  1256.             if (e_rcvd != e_funcs) {
  1257.                 if (e_funcs & ~e_rcvd) {
  1258.                     /*
  1259.                      * They've removed something.  This is
  1260.                      * technically illegal, but we can
  1261.                      * live with it.
  1262.                      */
  1263.                     e_funcs = e_rcvd;
  1264.                 } else {
  1265.                     /*
  1266.                      * They've added something.  Abandon
  1267.                      * TN3270E, they're brain dead.
  1268.                      */
  1269.                     vtrace_str("Host illegally added "
  1270.                         "function(s), aborting "
  1271.                         "TN3270E\n");
  1272.                     wont_opt[2] = TELOPT_TN3270E;
  1273.                     net_rawout(wont_opt, sizeof(wont_opt));
  1274.                     vtrace_str("SENT %s %s\n", cmd(WONT),
  1275.                         opt(TELOPT_TN3270E));
  1276.                     myopts[TELOPT_TN3270E] = 0;
  1277.                     check_in3270();
  1278.                     break;
  1279.                 }
  1280.             }
  1281.             tn3270e_negotiated = 1;
  1282.             vtrace_str("TN3270E option negotiation complete.\n");
  1283.             check_in3270();
  1284.             break;
  1285.  
  1286.         default:
  1287.             vtrace_str("??%u SE\n", sbbuf[2]);
  1288.             break;
  1289.         }
  1290.         break;
  1291.  
  1292.     default:
  1293.         vtrace_str("??%u SE\n", sbbuf[1]);
  1294.     }
  1295.  
  1296.     /* Good enough for now. */
  1297.     return 0;
  1298. }
  1299.  
  1300. /* Expand a string of TN3270E function codes into text. */
  1301. static const char *
  1302. tn3270e_function_names(const unsigned char *buf, int len)
  1303. {
  1304.     int i;
  1305.     static char text_buf[1024];
  1306.     char *s = text_buf;
  1307.  
  1308.     if (!len)
  1309.         return("(null)");
  1310.     for (i = 0; i < len; i++) {
  1311.         s += sprintf(s, "%s%s", (s == text_buf) ? "" : " ",
  1312.             fnn(buf[i]));
  1313.     }
  1314.     return text_buf;
  1315. }
  1316.  
  1317. /* Expand the current TN3270E function codes into text. */
  1318. const char *
  1319. tn3270e_current_opts(void)
  1320. {
  1321.     int i;
  1322.     static char text_buf[1024];
  1323.     char *s = text_buf;
  1324.  
  1325.     if (!e_funcs || !IN_E)
  1326.         return CN;
  1327.     for (i = 0; i < 32; i++) {
  1328.         if (e_funcs & E_OPT(i))
  1329.         s += sprintf(s, "%s%s", (s == text_buf) ? "" : " ",
  1330.             fnn(i));
  1331.     }
  1332.     return text_buf;
  1333. }
  1334.  
  1335. /* Transmit a TN3270E FUNCTIONS REQUEST or FUNCTIONS IS message. */
  1336. static void
  1337. tn3270e_subneg_send(unsigned char op, unsigned long funcs)
  1338. {
  1339.     unsigned char proto_buf[7 + 32];
  1340.     int proto_len;
  1341.     int i;
  1342.  
  1343.     /* Construct the buffers. */
  1344.     (void) memcpy(proto_buf, functions_req, 4);
  1345.     proto_buf[4] = op;
  1346.     proto_len = 5;
  1347.     for (i = 0; i < 32; i++) {
  1348.         if (funcs & E_OPT(i))
  1349.             proto_buf[proto_len++] = i;
  1350.     }
  1351.  
  1352.     /* Complete and send out the protocol message. */
  1353.     proto_buf[proto_len++] = IAC;
  1354.     proto_buf[proto_len++] = SE;
  1355.     net_rawout(proto_buf, proto_len);
  1356.  
  1357.     /* Complete and send out the trace text. */
  1358.     vtrace_str("SENT %s %s FUNCTIONS %s %s %s\n",
  1359.         cmd(SB), opt(TELOPT_TN3270E),
  1360.         (op == TN3270E_OP_REQUEST)? "REQUEST": "IS",
  1361.         tn3270e_function_names(proto_buf + 5, proto_len - 7),
  1362.         cmd(SE));
  1363. }
  1364.  
  1365. /* Translate a string of TN3270E functions into a bit-map. */
  1366. static unsigned long
  1367. tn3270e_fdecode(const unsigned char *buf, int len)
  1368. {
  1369.     unsigned long r = 0L;
  1370.     int i;
  1371.  
  1372.     /* Note that this code silently ignores options >= 32. */
  1373.     for (i = 0; i < len; i++) {
  1374.         if (buf[i] < 32)
  1375.             r |= E_OPT(buf[i]);
  1376.     }
  1377.     return r;
  1378. }
  1379. #endif /*]*/
  1380.  
  1381. static int
  1382. process_eor(void)
  1383. {
  1384.     if (syncing || !(ibptr - ibuf))
  1385.         return(0);
  1386.  
  1387. #if defined(X3270_TN3270E) /*[*/
  1388.     if (IN_E) {
  1389.         tn3270e_header *h = (tn3270e_header *)ibuf;
  1390.         unsigned char *s;
  1391.         enum pds rv;
  1392.  
  1393.         vtrace_str("RCVD TN3270E(%s%s %s %u)\n",
  1394.             e_dt(h->data_type),
  1395.             e_rq(h->data_type, h->request_flag),
  1396.             e_rsp(h->data_type, h->response_flag),
  1397.             h->seq_number[0] << 8 | h->seq_number[1]);
  1398.  
  1399.         switch (h->data_type) {
  1400.         case TN3270E_DT_3270_DATA:
  1401.             if ((e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)) &&
  1402.                 !tn3270e_bound)
  1403.                 return 0;
  1404.             tn3270e_submode = E_3270;
  1405.             check_in3270();
  1406.             response_required = h->response_flag;
  1407.             rv = process_ds(ibuf + EH_SIZE,
  1408.                 (ibptr - ibuf) - EH_SIZE);
  1409.             if (rv < 0 &&
  1410.                 response_required != TN3270E_RSF_NO_RESPONSE)
  1411.                 tn3270e_nak(rv);
  1412.             else if (rv == PDS_OKAY_NO_OUTPUT &&
  1413.                 response_required == TN3270E_RSF_ALWAYS_RESPONSE)
  1414.                 tn3270e_ack();
  1415.             response_required = TN3270E_RSF_NO_RESPONSE;
  1416.             return 0;
  1417.         case TN3270E_DT_BIND_IMAGE:
  1418.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1419.                 return 0;
  1420.             tn3270e_bound = 1;
  1421.             check_in3270();
  1422.             return 0;
  1423.         case TN3270E_DT_UNBIND:
  1424.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1425.                 return 0;
  1426.             tn3270e_bound = 0;
  1427.             if (tn3270e_submode == E_3270)
  1428.                 tn3270e_submode = E_NONE;
  1429.             check_in3270();
  1430.             return 0;
  1431.         case TN3270E_DT_NVT_DATA:
  1432.             /* In tn3270e NVT mode */
  1433.             tn3270e_submode = E_NVT;
  1434.             check_in3270();
  1435.             for (s = ibuf; s < ibptr; s++) {
  1436.                 ansi_process(*s++);
  1437.             }
  1438.             return 0;
  1439.         case TN3270E_DT_SSCP_LU_DATA:
  1440.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1441.                 return 0;
  1442.             tn3270e_submode = E_SSCP;
  1443.             check_in3270();
  1444.             ctlr_write_sscp_lu(ibuf + EH_SIZE,
  1445.                                (ibptr - ibuf) - EH_SIZE);
  1446.             return 0;
  1447.         default:
  1448.             /* Should do something more extraordinary here. */
  1449.             return 0;
  1450.         }
  1451.     } else
  1452. #endif /*]*/
  1453.     {
  1454.         (void) process_ds(ibuf, ibptr - ibuf);
  1455.     }
  1456.     return 0;
  1457. }
  1458.  
  1459.  
  1460. /*
  1461.  * net_exception
  1462.  *    Called when there is an exceptional condition on the socket.
  1463.  */
  1464. void
  1465. net_exception(void)
  1466. {
  1467.     trace_str("RCVD urgent data indication\n");
  1468.     if (!syncing) {
  1469.         syncing = 1;
  1470.         x_except_off();
  1471.     }
  1472. }
  1473.  
  1474. /*
  1475.  * Flavors of Network Output:
  1476.  *
  1477.  *   3270 mode
  1478.  *    net_output    send a 3270 record
  1479.  *
  1480.  *   ANSI mode; call each other in turn
  1481.  *    net_sendc    net_cookout for 1 byte
  1482.  *    net_sends    net_cookout for a null-terminated string
  1483.  *    net_cookout    send user data with cooked-mode processing, ANSI mode
  1484.  *    net_cookedout    send user data, ANSI mode, already cooked
  1485.  *    net_rawout    send telnet protocol data, ANSI mode
  1486.  *
  1487.  */
  1488.  
  1489.  
  1490. /*
  1491.  * net_rawout
  1492.  *    Send out raw telnet data.  We assume that there will always be enough
  1493.  *    space to buffer what we want to transmit, so we don't handle EAGAIN or
  1494.  *    EWOULDBLOCK.
  1495.  */
  1496. static void
  1497. net_rawout(unsigned const char *buf, int len)
  1498. {
  1499.     int    nw;
  1500.  
  1501. #if defined(X3270_TRACE) /*[*/
  1502.     trace_netdata('>', buf, len);
  1503. #endif /*]*/
  1504.  
  1505.     while (len) {
  1506. #if defined(OMTU) /*[*/
  1507.         int n2w = len;
  1508.         int pause = 0;
  1509.  
  1510.         if (n2w > OMTU) {
  1511.             n2w = OMTU;
  1512.             pause = 1;
  1513.         }
  1514. #else
  1515. #        define n2w len
  1516. #endif
  1517.         nw = write(sock, (const char *) buf, n2w);
  1518.         if (nw < 0) {
  1519.             vtrace_str("RCVD socket error %d\n", errno);
  1520.             if (errno == EPIPE || errno == ECONNRESET) {
  1521.                 host_disconnect(False);
  1522.                 return;
  1523.             } else if (errno == EINTR) {
  1524.                 goto bot;
  1525.             } else {
  1526.                 popup_an_errno(errno, "Socket write");
  1527.                 host_disconnect(True);
  1528.                 return;
  1529.             }
  1530.         }
  1531.         ns_bsent += nw;
  1532.         len -= nw;
  1533.         buf += nw;
  1534.         bot:
  1535. #if defined(OMTU) /*[*/
  1536.         if (pause)
  1537.             sleep(1);
  1538. #endif /*]*/
  1539.         ;
  1540.     }
  1541. }
  1542.  
  1543.  
  1544. #if defined(X3270_ANSI) /*[*/
  1545. /*
  1546.  * net_hexansi_out
  1547.  *    Send uncontrolled user data to the host in ANSI mode, performing IAC
  1548.  *    and CR quoting as necessary.
  1549.  */
  1550. void
  1551. net_hexansi_out(unsigned char *buf, int len)
  1552. {
  1553.     unsigned char *tbuf;
  1554.     unsigned char *xbuf;
  1555.  
  1556.     if (!len)
  1557.         return;
  1558.  
  1559. #if defined(X3270_TRACE) /*[*/
  1560.     /* Trace the data. */
  1561.     if (toggled(DS_TRACE)) {
  1562.         int i;
  1563.  
  1564.         (void) fprintf(tracef, ">");
  1565.         for (i = 0; i < len; i++)
  1566.             (void) fprintf(tracef, " %s", ctl_see((int) *(buf+i)));
  1567.         (void) fprintf(tracef, "\n");
  1568.     }
  1569. #endif /*]*/
  1570.  
  1571.     /* Expand it. */
  1572.     tbuf = xbuf = (unsigned char *)Malloc(2*len);
  1573.     while (len) {
  1574.         unsigned char c = *buf++;
  1575.  
  1576.         *tbuf++ = c;
  1577.         len--;
  1578.         if (c == IAC)
  1579.             *tbuf++ = IAC;
  1580.         else if (c == '\r' && (!len || *buf != '\n'))
  1581.             *tbuf++ = '\0';
  1582.     }
  1583.  
  1584.     /* Send it to the host. */
  1585.     net_rawout(xbuf, tbuf - xbuf);
  1586.     Free((XtPointer)xbuf);
  1587. }
  1588.  
  1589. /*
  1590.  * net_cookedout
  1591.  *    Send user data out in ANSI mode, without cooked-mode processing.
  1592.  */
  1593. static void
  1594. net_cookedout(const char *buf, int len)
  1595. {
  1596. #if defined(X3270_TRACE) /*[*/
  1597.     if (toggled(DS_TRACE)) {
  1598.         int i;
  1599.  
  1600.         (void) fprintf(tracef, ">");
  1601.         for (i = 0; i < len; i++)
  1602.             (void) fprintf(tracef, " %s", ctl_see((int) *(buf+i)));
  1603.         (void) fprintf(tracef, "\n");
  1604.     }
  1605. #endif /*]*/
  1606.     net_rawout((unsigned const char *) buf, len);
  1607. }
  1608.  
  1609.  
  1610. /*
  1611.  * net_cookout
  1612.  *    Send output in ANSI mode, including cooked-mode processing if
  1613.  *    appropriate.
  1614.  */
  1615. static void
  1616. net_cookout(const char *buf, int len)
  1617. {
  1618.  
  1619.     if (!IN_ANSI || (kybdlock & KL_AWAITING_FIRST))
  1620.         return;
  1621.  
  1622.     if (linemode) {
  1623.         register int    i;
  1624.         char    c;
  1625.  
  1626.         for (i = 0; i < len; i++) {
  1627.             c = buf[i];
  1628.  
  1629.             /* Input conversions. */
  1630.             if (!lnext && c == '\r' && appres.icrnl)
  1631.                 c = '\n';
  1632.             else if (!lnext && c == '\n' && appres.inlcr)
  1633.                 c = '\r';
  1634.  
  1635.             /* Backslashes. */
  1636.             if (c == '\\' && !backslashed)
  1637.                 backslashed = 1;
  1638.             else
  1639.                 backslashed = 0;
  1640.  
  1641.             /* Control chars. */
  1642.             if (c == '\n')
  1643.                 do_eol(c);
  1644.             else if (c == vintr)
  1645.                 do_intr(c);
  1646.             else if (c == vquit)
  1647.                 do_quit(c);
  1648.             else if (c == verase)
  1649.                 do_cerase(c);
  1650.             else if (c == vkill)
  1651.                 do_kill(c);
  1652.             else if (c == vwerase)
  1653.                 do_werase(c);
  1654.             else if (c == vrprnt)
  1655.                 do_rprnt(c);
  1656.             else if (c == veof)
  1657.                 do_eof(c);
  1658.             else if (c == vlnext)
  1659.                 do_lnext(c);
  1660.             else
  1661.                 do_data(c);
  1662.         }
  1663.         return;
  1664.     } else
  1665.         net_cookedout(buf, len);
  1666. }
  1667.  
  1668.  
  1669. /*
  1670.  * Cooked mode input processing.
  1671.  */
  1672.  
  1673. static void
  1674. cooked_init(void)
  1675. {
  1676.     if (lbuf == (unsigned char *)NULL)
  1677.         lbuf = (unsigned char *)Malloc(BUFSZ);
  1678.     lbptr = lbuf;
  1679.     lnext = 0;
  1680.     backslashed = 0;
  1681. }
  1682.  
  1683. static void
  1684. ansi_process_s(const char *data)
  1685. {
  1686.     while (*data)
  1687.         ansi_process((unsigned int) *data++);
  1688. }
  1689.  
  1690. static void
  1691. forward_data(void)
  1692. {
  1693.     net_cookedout((char *) lbuf, lbptr - lbuf);
  1694.     cooked_init();
  1695. }
  1696.  
  1697. static void
  1698. do_data(char c)
  1699. {
  1700.     if (lbptr+1 < lbuf + BUFSZ) {
  1701.         *lbptr++ = c;
  1702.         if (c == '\r')
  1703.             *lbptr++ = '\0';
  1704.         if (c == '\t')
  1705.             ansi_process((unsigned int) c);
  1706.         else
  1707.             ansi_process_s(ctl_see((int) c));
  1708.     } else
  1709.         ansi_process_s("\007");
  1710.     lnext = 0;
  1711.     backslashed = 0;
  1712. }
  1713.  
  1714. static void
  1715. do_intr(char c)
  1716. {
  1717.     if (lnext) {
  1718.         do_data(c);
  1719.         return;
  1720.     }
  1721.     ansi_process_s(ctl_see((int) c));
  1722.     cooked_init();
  1723.     net_interrupt();
  1724. }
  1725.  
  1726. static void
  1727. do_quit(char c)
  1728. {
  1729.     if (lnext) {
  1730.         do_data(c);
  1731.         return;
  1732.     }
  1733.     ansi_process_s(ctl_see((int) c));
  1734.     cooked_init();
  1735.     net_break();
  1736. }
  1737.  
  1738. static void
  1739. do_cerase(char c)
  1740. {
  1741.     int len;
  1742.  
  1743.     if (backslashed) {
  1744.         lbptr--;
  1745.         ansi_process_s("\b");
  1746.         do_data(c);
  1747.         return;
  1748.     }
  1749.     if (lnext) {
  1750.         do_data(c);
  1751.         return;
  1752.     }
  1753.     if (lbptr > lbuf) {
  1754.         len = strlen(ctl_see((int) *--lbptr));
  1755.  
  1756.         while (len--)
  1757.             ansi_process_s("\b \b");
  1758.     }
  1759. }
  1760.  
  1761. static void
  1762. do_werase(char c)
  1763. {
  1764.     int any = 0;
  1765.     int len;
  1766.  
  1767.     if (lnext) {
  1768.         do_data(c);
  1769.         return;
  1770.     }
  1771.     while (lbptr > lbuf) {
  1772.         char ch = *--lbptr;
  1773.  
  1774.         if (ch == ' ' || ch == '\t') {
  1775.             if (any) {
  1776.                 ++lbptr;
  1777.                 break;
  1778.             }
  1779.         } else
  1780.             any = 1;
  1781.         len = strlen(ctl_see((int) ch));
  1782.  
  1783.         while (len--)
  1784.             ansi_process_s("\b \b");
  1785.     }
  1786. }
  1787.  
  1788. static void
  1789. do_kill(char c)
  1790. {
  1791.     int i, len;
  1792.  
  1793.     if (backslashed) {
  1794.         lbptr--;
  1795.         ansi_process_s("\b");
  1796.         do_data(c);
  1797.         return;
  1798.     }
  1799.     if (lnext) {
  1800.         do_data(c);
  1801.         return;
  1802.     }
  1803.     while (lbptr > lbuf) {
  1804.         len = strlen(ctl_see((int) *--lbptr));
  1805.  
  1806.         for (i = 0; i < len; i++)
  1807.             ansi_process_s("\b \b");
  1808.     }
  1809. }
  1810.  
  1811. static void
  1812. do_rprnt(char c)
  1813. {
  1814.     unsigned char *p;
  1815.  
  1816.     if (lnext) {
  1817.         do_data(c);
  1818.         return;
  1819.     }
  1820.     ansi_process_s(ctl_see((int) c));
  1821.     ansi_process_s("\r\n");
  1822.     for (p = lbuf; p < lbptr; p++)
  1823.         ansi_process_s(ctl_see((int) *p));
  1824. }
  1825.  
  1826. static void
  1827. do_eof(char c)
  1828. {
  1829.     if (backslashed) {
  1830.         lbptr--;
  1831.         ansi_process_s("\b");
  1832.         do_data(c);
  1833.         return;
  1834.     }
  1835.     if (lnext) {
  1836.         do_data(c);
  1837.         return;
  1838.     }
  1839.     do_data(c);
  1840.     forward_data();
  1841. }
  1842.  
  1843. static void
  1844. do_eol(char c)
  1845. {
  1846.     if (lnext) {
  1847.         do_data(c);
  1848.         return;
  1849.     }
  1850.     if (lbptr+2 >= lbuf + BUFSZ) {
  1851.         ansi_process_s("\007");
  1852.         return;
  1853.     }
  1854.     *lbptr++ = '\r';
  1855.     *lbptr++ = '\n';
  1856.     ansi_process_s("\r\n");
  1857.     forward_data();
  1858. }
  1859.  
  1860. static void
  1861. do_lnext(char c)
  1862. {
  1863.     if (lnext) {
  1864.         do_data(c);
  1865.         return;
  1866.     }
  1867.     lnext = 1;
  1868.     ansi_process_s("^\b");
  1869. }
  1870. #endif /*]*/
  1871.  
  1872.  
  1873.  
  1874. /*
  1875.  * check_in3270
  1876.  *    Check for switches between NVT, SSCP-LU and 3270 modes.
  1877.  */
  1878. static void
  1879. check_in3270(void)
  1880. {
  1881.     enum cstate new_cstate = NOT_CONNECTED;
  1882.     static const char *state_name[] = {
  1883.         "unconnected",
  1884.         "pending",
  1885.         "connected initial",
  1886.         "TN3270 NVT",
  1887.         "TN3270 3270",
  1888.         "TN3270E",
  1889.         "TN3270E NVT",
  1890.         "TN3270E SSCP-LU",
  1891.         "TN3270E 3270"
  1892.     };
  1893.  
  1894. #if defined(X3270_TN3270E) /*[*/
  1895.     if (myopts[TELOPT_TN3270E]) {
  1896.         if (!tn3270e_negotiated)
  1897.             new_cstate = CONNECTED_INITIAL_E;
  1898.         else switch (tn3270e_submode) {
  1899.         case E_NONE:
  1900.             new_cstate = CONNECTED_INITIAL_E;
  1901.             break;
  1902.         case E_NVT:
  1903.             new_cstate = CONNECTED_NVT;
  1904.             break;
  1905.         case E_3270:
  1906.             new_cstate = CONNECTED_TN3270E;
  1907.             break;
  1908.         case E_SSCP:
  1909.             new_cstate = CONNECTED_SSCP;
  1910.             break;
  1911.         }
  1912.     } else
  1913. #endif /*]*/
  1914.     if (myopts[TELOPT_BINARY] &&
  1915.                myopts[TELOPT_EOR] &&
  1916.                myopts[TELOPT_TTYPE] &&
  1917.                hisopts[TELOPT_BINARY] &&
  1918.                hisopts[TELOPT_EOR]) {
  1919.         new_cstate = CONNECTED_3270;
  1920.     } else if (cstate == CONNECTED_INITIAL) {
  1921.         /* Nothing has happened, yet. */
  1922.         return;
  1923.     } else {
  1924.         new_cstate = CONNECTED_ANSI;
  1925.     }
  1926.  
  1927.     if (new_cstate != cstate) {
  1928. #if defined(X3270_TN3270E) /*[*/
  1929.         int was_in_e = IN_E;
  1930. #endif /*]*/
  1931.  
  1932.         vtrace_str("Now operating in %s mode.\n",
  1933.             state_name[new_cstate]);
  1934.         host_in3270(new_cstate);
  1935.  
  1936. #if defined(X3270_TN3270E) /*[*/
  1937.         /*
  1938.          * If we've now switched between non-TN3270E mode and
  1939.          * TN3270E mode, reset the LU list so we can try again
  1940.          * in the new mode.
  1941.          */
  1942.         if (lus != (char **)NULL && was_in_e != IN_E) {
  1943.             curr_lu = lus;
  1944.             try_lu = *curr_lu;
  1945.         }
  1946. #endif /*]*/
  1947.  
  1948.         /* Allocate the initial 3270 input buffer. */
  1949.         if (new_cstate >= CONNECTED_INITIAL && !ibuf_size) {
  1950.             ibuf = (unsigned char *)Malloc(BUFSIZ);
  1951.             ibuf_size = BUFSIZ;
  1952.             ibptr = ibuf;
  1953.         }
  1954.  
  1955. #if defined(X3270_ANSI) /*[*/
  1956.         /* Reinitialize line mode. */
  1957.         if ((new_cstate == CONNECTED_ANSI && linemode) ||
  1958.             new_cstate == CONNECTED_NVT)
  1959.             cooked_init();
  1960. #endif /*]*/
  1961.  
  1962. #if defined(X3270_TN3270E) /*[*/
  1963.         /* If we fell out of TN3270E, remove the state. */
  1964.         if (!myopts[TELOPT_TN3270E]) {
  1965.             tn3270e_negotiated = 0;
  1966.             tn3270e_submode = E_NONE;
  1967.             tn3270e_bound = 0;
  1968.         }
  1969. #endif /*]*/
  1970.     }
  1971. }
  1972.  
  1973. /*
  1974.  * store3270in
  1975.  *    Store a character in the 3270 input buffer, checking for buffer
  1976.  *    overflow and reallocating ibuf if necessary.
  1977.  */
  1978. static void
  1979. store3270in(unsigned char c)
  1980. {
  1981.     if (ibptr - ibuf >= ibuf_size) {
  1982.         ibuf_size += BUFSIZ;
  1983.         ibuf = (unsigned char *)Realloc((char *)ibuf, ibuf_size);
  1984.         ibptr = ibuf + ibuf_size - BUFSIZ;
  1985.     }
  1986.     *ibptr++ = c;
  1987. }
  1988.  
  1989. /*
  1990.  * space3270out
  1991.  *    Ensure that <n> more characters will fit in the 3270 output buffer.
  1992.  *    Allocates the buffer in BUFSIZ chunks.
  1993.  *    Allocates hidden space at the front of the buffer for TN3270E.
  1994.  */
  1995. void
  1996. space3270out(int n)
  1997. {
  1998.     unsigned nc = 0;    /* amount of data currently in obuf */
  1999.     unsigned more = 0;
  2000.  
  2001.     if (obuf_size)
  2002.         nc = obptr - obuf;
  2003.  
  2004.     while ((nc + n + EH_SIZE) > (obuf_size + more)) {
  2005.         more += BUFSIZ;
  2006.     }
  2007.  
  2008.     if (more) {
  2009.         obuf_size += more;
  2010.         obuf_base = (unsigned char *)Realloc((char *)obuf_base,
  2011.             obuf_size);
  2012.         obuf = obuf_base + EH_SIZE;
  2013.         obptr = obuf + nc;
  2014.     }
  2015. }
  2016.  
  2017.  
  2018. /*
  2019.  * check_linemode
  2020.  *    Set the global variable 'linemode', which says whether we are in
  2021.  *    character-by-character mode or line mode.
  2022.  */
  2023. static void
  2024. check_linemode(Boolean init)
  2025. {
  2026.     int wasline = linemode;
  2027.  
  2028.     /*
  2029.      * The next line is a deliberate kluge to effectively ignore the SGA
  2030.      * option.  If the host will echo for us, we assume
  2031.      * character-at-a-time; otherwise we assume fully cooked by us.
  2032.      *
  2033.      * This allows certain IBM hosts which volunteer SGA but refuse
  2034.      * ECHO to operate more-or-less normally, at the expense of
  2035.      * implementing the (hopefully useless) "character-at-a-time, local
  2036.      * echo" mode.
  2037.      *
  2038.      * We still implement "switch to line mode" and "switch to character
  2039.      * mode" properly by asking for both SGA and ECHO to be off or on, but
  2040.      * we basically ignore the reply for SGA.
  2041.      */
  2042.     linemode = !hisopts[TELOPT_ECHO] /* && !hisopts[TELOPT_SGA] */;
  2043.  
  2044.     if (init || linemode != wasline) {
  2045.         st_changed(ST_LINE_MODE, linemode);
  2046.         if (!init) {
  2047.             vtrace_str("Operating in %s mode.\n",
  2048.                 linemode ? "line" : "character-at-a-time");
  2049.         }
  2050. #if defined(X3270_ANSI) /*[*/
  2051.         if (IN_ANSI && linemode)
  2052.             cooked_init();
  2053. #endif /*]*/
  2054.     }
  2055. }
  2056.  
  2057.  
  2058. #if defined(X3270_TRACE) /*[*/
  2059.  
  2060. /*
  2061.  * nnn
  2062.  *    Expands a number to a character string, for displaying unknown telnet
  2063.  *    commands and options.
  2064.  */
  2065. static const char *
  2066. nnn(int c)
  2067. {
  2068.     static char    buf[64];
  2069.  
  2070.     (void) sprintf(buf, "%d", c);
  2071.     return buf;
  2072. }
  2073.  
  2074. /*
  2075.  * cmd
  2076.  *    Expands a TELNET command into a character string.
  2077.  */
  2078. static const char *
  2079. cmd(unsigned char c)
  2080. {
  2081.     if (TELCMD_OK(c))
  2082.         return TELCMD(c);
  2083.     else
  2084.         return nnn((int)c);
  2085. }
  2086.  
  2087. /*
  2088.  * opt
  2089.  *    Expands a TELNET option into a character string.
  2090.  */
  2091. static const char *
  2092. opt(unsigned char c)
  2093. {
  2094.     if (TELOPT_OK(c))
  2095.         return TELOPT(c);
  2096.     else if (c == TELOPT_TN3270E)
  2097.         return "TN3270E";
  2098.     else
  2099.         return nnn((int)c);
  2100. }
  2101.  
  2102.  
  2103. #define LINEDUMP_MAX    32
  2104.  
  2105. void
  2106. trace_netdata(char direction, unsigned const char *buf, int len)
  2107. {
  2108.     int offset;
  2109.     struct timeval ts;
  2110.     double tdiff;
  2111.  
  2112.     if (!toggled(DS_TRACE))
  2113.         return;
  2114.     (void) gettimeofday(&ts, (struct timezone *)NULL);
  2115.     if (IN_3270) {
  2116.         tdiff = ((1.0e6 * (double)(ts.tv_sec - ds_ts.tv_sec)) +
  2117.             (double)(ts.tv_usec - ds_ts.tv_usec)) / 1.0e6;
  2118.         (void) fprintf(tracef, "%c +%gs\n", direction, tdiff);
  2119.     }
  2120.     ds_ts = ts;
  2121.     for (offset = 0; offset < len; offset++) {
  2122.         if (!(offset % LINEDUMP_MAX))
  2123.             (void) fprintf(tracef, "%s%c 0x%-3x ",
  2124.                 (offset ? "\n" : ""), direction, offset);
  2125.         (void) fprintf(tracef, "%02x", buf[offset]);
  2126.     }
  2127.     (void) fprintf(tracef, "\n");
  2128. }
  2129. #endif /*]*/
  2130.  
  2131.  
  2132. /*
  2133.  * net_output
  2134.  *    Send 3270 output over the network, prepending TN3270E headers and
  2135.  *    tacking on the necessary telnet end-of-record command.
  2136.  */
  2137. void
  2138. net_output(void)
  2139. {
  2140. #if defined(X3270_TN3270E) /*[*/
  2141. #define BSTART    ((IN_TN3270E || IN_SSCP) ? obuf_base : obuf)
  2142. #else /*][*/
  2143. #define BSTART    obuf
  2144. #endif /*]*/
  2145.  
  2146. #if defined(X3270_TN3270E) /*[*/
  2147.     /* Set the TN3720E header. */
  2148.     if (IN_TN3270E || IN_SSCP) {
  2149.         tn3270e_header *h = (tn3270e_header *)obuf_base;
  2150.  
  2151.         /* Check for sending a TN3270E response. */
  2152.         if (response_required == TN3270E_RSF_ALWAYS_RESPONSE) {
  2153.             tn3270e_ack();
  2154.             response_required = TN3270E_RSF_NO_RESPONSE;
  2155.         }
  2156.  
  2157.         /* Set the outbound TN3270E header. */
  2158.         h->data_type = IN_TN3270E ?
  2159.             TN3270E_DT_3270_DATA : TN3270E_DT_SSCP_LU_DATA;
  2160.         h->request_flag = 0;
  2161.         h->response_flag = 0;
  2162.         h->seq_number[0] = (e_xmit_seq >> 8) & 0xff;
  2163.         h->seq_number[1] = e_xmit_seq & 0xff;
  2164.     }
  2165. #endif /*]*/
  2166.  
  2167.     /* Count the number of IACs in the message. */
  2168.     {
  2169.         char *buf = (char *)BSTART;
  2170.         int len = obptr - BSTART;
  2171.         char *iac;
  2172.         int cnt = 0;
  2173.  
  2174.         while (len && (iac = memchr(buf, IAC, len)) != CN) {
  2175.             cnt++;
  2176.             len -= iac - buf + 1;
  2177.             buf = iac + 1;
  2178.         }
  2179.         if (cnt) {
  2180.             space3270out(cnt);
  2181.             len = obptr - BSTART;
  2182.             buf = (char *)BSTART;
  2183.  
  2184.             /* Now quote them. */
  2185.             while (len && (iac = memchr(buf, IAC, len)) != CN) {
  2186.                 int ml = len - (iac - buf);
  2187.  
  2188.                 (void) memmove(iac + 1, iac, ml);
  2189.                 len -= iac - buf + 1;
  2190.                 buf = iac + 2;
  2191.                 obptr++;
  2192.             }
  2193.         }
  2194.     }
  2195.  
  2196.     /* Add IAC EOR to the end and send it. */
  2197.     space3270out(2);
  2198.     *obptr++ = IAC;
  2199.     *obptr++ = EOR;
  2200. #if defined(X3270_TN3270E) /*[*/
  2201.     if (IN_TN3270E || IN_SSCP) {
  2202.         vtrace_str("SENT TN3270E(%s NO-RESPONSE %u)\n",
  2203.             IN_TN3270E ? "3270-DATA" : "SSCP-LU-DATA", e_xmit_seq);
  2204.         if (e_funcs & E_OPT(TN3270E_FUNC_RESPONSES))
  2205.             e_xmit_seq = (e_xmit_seq + 1) & 0x7fff;
  2206.     }
  2207. #endif /*]*/
  2208.     net_rawout(BSTART, obptr - BSTART);
  2209.  
  2210.     trace_str("SENT EOR\n");
  2211.     ns_rsent++;
  2212. #undef BSTART
  2213. }
  2214.  
  2215. #if defined(X3270_TN3270E) /*[*/
  2216. /* Send a TN3270E positive response to the server. */
  2217. static void
  2218. tn3270e_ack(void)
  2219. {
  2220.     unsigned char rsp_buf[9];
  2221.     tn3270e_header *h, *h_in;
  2222.     int rsp_len = EH_SIZE;
  2223.  
  2224.     h = (tn3270e_header *)rsp_buf;
  2225.     h_in = (tn3270e_header *)ibuf;
  2226.  
  2227.     h->data_type = TN3270E_DT_RESPONSE;
  2228.     h->request_flag = 0;
  2229.     h->response_flag = TN3270E_RSF_POSITIVE_RESPONSE;
  2230.     h->seq_number[0] = h_in->seq_number[0];
  2231.     h->seq_number[1] = h_in->seq_number[1];
  2232.     if (h->seq_number[1] == IAC)
  2233.         rsp_buf[rsp_len++] = IAC;
  2234.     rsp_buf[rsp_len++] = TN3270E_POS_DEVICE_END;
  2235.     rsp_buf[rsp_len++] = IAC;
  2236.     rsp_buf[rsp_len++] = EOR;
  2237.     vtrace_str("SENT TN3270E(RESPONSE POSITIVE-RESPONSE "
  2238.         "%u) DEVICE-END\n",
  2239.         h_in->seq_number[0] << 8 | h_in->seq_number[1]);
  2240.     net_rawout(rsp_buf, rsp_len);
  2241. }
  2242.  
  2243. /* Send a TN3270E negative response to the server. */
  2244. static void
  2245. tn3270e_nak(enum pds rv unused)
  2246. {
  2247.     unsigned char rsp_buf[9];
  2248.     tn3270e_header *h, *h_in;
  2249.     int rsp_len = EH_SIZE;
  2250.  
  2251.     h = (tn3270e_header *)rsp_buf;
  2252.     h_in = (tn3270e_header *)ibuf;
  2253.  
  2254.     h->data_type = TN3270E_DT_RESPONSE;
  2255.     h->request_flag = 0;
  2256.     h->response_flag = TN3270E_RSF_NEGATIVE_RESPONSE;
  2257.     h->seq_number[0] = h_in->seq_number[0];
  2258.     h->seq_number[1] = h_in->seq_number[1];
  2259.     if (h->seq_number[1] == IAC)
  2260.         rsp_buf[rsp_len++] = IAC;
  2261.     rsp_buf[rsp_len++] = TN3270E_NEG_COMMAND_REJECT;
  2262.     rsp_buf[rsp_len++] = IAC;
  2263.     rsp_buf[rsp_len++] = EOR;
  2264.     vtrace_str("SENT TN3270E(RESPONSE NEGATIVE-RESPONSE %u) "
  2265.         "COMMAND-REJECT\n",
  2266.         h_in->seq_number[0] << 8 | h_in->seq_number[1]);
  2267.     net_rawout(rsp_buf, rsp_len);
  2268. }
  2269.  
  2270. #if defined(X3270_TRACE) /*[*/
  2271. /* Add a dummy TN3270E header to the output buffer. */
  2272. Boolean
  2273. net_add_dummy_tn3270e(void)
  2274. {
  2275.     tn3270e_header *h;
  2276.  
  2277.     if (!IN_E || tn3270e_submode == E_NONE)
  2278.         return False;
  2279.  
  2280.     space3270out(EH_SIZE);
  2281.     h = (tn3270e_header *)obptr;
  2282.  
  2283.     switch (tn3270e_submode) {
  2284.     case E_NONE:
  2285.         break;
  2286.     case E_NVT:
  2287.         h->data_type = TN3270E_DT_NVT_DATA;
  2288.         break;
  2289.     case E_SSCP:
  2290.         h->data_type = TN3270E_DT_SSCP_LU_DATA;
  2291.         break;
  2292.     case E_3270:
  2293.         h->data_type = TN3270E_DT_3270_DATA;
  2294.         break;
  2295.     }
  2296.     h->request_flag = 0;
  2297.     h->response_flag = TN3270E_RSF_NO_RESPONSE;
  2298.     h->seq_number[0] = 0;
  2299.     h->seq_number[1] = 0;
  2300.     obptr += EH_SIZE;
  2301.     return True;
  2302. }
  2303. #endif /*]*/
  2304. #endif /*]*/
  2305.  
  2306. #if defined(X3270_TRACE) /*[*/
  2307. /*
  2308.  * Add IAC EOR to a buffer.
  2309.  */
  2310. void
  2311. net_add_eor(unsigned char *buf, int len)
  2312. {
  2313.     buf[len++] = IAC;
  2314.     buf[len++] = EOR;
  2315. }
  2316. #endif /*]*/
  2317.  
  2318.  
  2319. #if defined(X3270_ANSI) /*[*/
  2320. /*
  2321.  * net_sendc
  2322.  *    Send a character of user data over the network in ANSI mode.
  2323.  */
  2324. void
  2325. net_sendc(char c)
  2326. {
  2327.     if (c == '\r' && !linemode
  2328. #if defined(LOCAL_PROCESS) /*[*/
  2329.                    && !local_process
  2330. #endif /*]*/
  2331.                             ) {
  2332.         /* CR must be quoted */
  2333.         net_cookout("\r\0", 2);
  2334.     } else {
  2335.         net_cookout(&c, 1);
  2336.     }
  2337. }
  2338.  
  2339.  
  2340. /*
  2341.  * net_sends
  2342.  *    Send a null-terminated string of user data in ANSI mode.
  2343.  */
  2344. void
  2345. net_sends(const char *s)
  2346. {
  2347.     net_cookout(s, strlen(s));
  2348. }
  2349.  
  2350.  
  2351. /*
  2352.  * net_send_erase
  2353.  *    Sends the KILL character in ANSI mode.
  2354.  */
  2355. void
  2356. net_send_erase(void)
  2357. {
  2358.     net_cookout(&verase, 1);
  2359. }
  2360.  
  2361.  
  2362. /*
  2363.  * net_send_kill
  2364.  *    Sends the KILL character in ANSI mode.
  2365.  */
  2366. void
  2367. net_send_kill(void)
  2368. {
  2369.     net_cookout(&vkill, 1);
  2370. }
  2371.  
  2372.  
  2373. /*
  2374.  * net_send_werase
  2375.  *    Sends the WERASE character in ANSI mode.
  2376.  */
  2377. void
  2378. net_send_werase(void)
  2379. {
  2380.     net_cookout(&vwerase, 1);
  2381. }
  2382. #endif /*]*/
  2383.  
  2384.  
  2385. #if defined(X3270_MENUS) /*[*/
  2386. /*
  2387.  * External entry points to negotiate line or character mode.
  2388.  */
  2389. void
  2390. net_linemode(void)
  2391. {
  2392.     if (!CONNECTED)
  2393.         return;
  2394.     if (hisopts[TELOPT_ECHO]) {
  2395.         dont_opt[2] = TELOPT_ECHO;
  2396.         net_rawout(dont_opt, sizeof(dont_opt));
  2397.         vtrace_str("SENT %s %s\n", cmd(DONT), opt(TELOPT_ECHO));
  2398.     }
  2399.     if (hisopts[TELOPT_SGA]) {
  2400.         dont_opt[2] = TELOPT_SGA;
  2401.         net_rawout(dont_opt, sizeof(dont_opt));
  2402.         vtrace_str("SENT %s %s\n", cmd(DONT), opt(TELOPT_SGA));
  2403.     }
  2404. }
  2405.  
  2406. void
  2407. net_charmode(void)
  2408. {
  2409.     if (!CONNECTED)
  2410.         return;
  2411.     if (!hisopts[TELOPT_ECHO]) {
  2412.         do_opt[2] = TELOPT_ECHO;
  2413.         net_rawout(do_opt, sizeof(do_opt));
  2414.         vtrace_str("SENT %s %s\n", cmd(DO), opt(TELOPT_ECHO));
  2415.     }
  2416.     if (!hisopts[TELOPT_SGA]) {
  2417.         do_opt[2] = TELOPT_SGA;
  2418.         net_rawout(do_opt, sizeof(do_opt));
  2419.         vtrace_str("SENT %s %s\n", cmd(DO), opt(TELOPT_SGA));
  2420.     }
  2421. }
  2422. #endif /*]*/
  2423.  
  2424.  
  2425. /*
  2426.  * net_break
  2427.  *    Send telnet break, which is used to implement 3270 ATTN.
  2428.  *
  2429.  */
  2430. void
  2431. net_break(void)
  2432. {
  2433.     static unsigned char buf[] = { IAC, BREAK };
  2434.  
  2435.     /* I don't know if we should first send TELNET synch ? */
  2436.     net_rawout(buf, sizeof(buf));
  2437.     trace_str("SENT BREAK\n");
  2438. }
  2439.  
  2440. /*
  2441.  * net_interrupt
  2442.  *    Send telnet IP.
  2443.  *
  2444.  */
  2445. void
  2446. net_interrupt(void)
  2447. {
  2448.     static unsigned char buf[] = { IAC, IP };
  2449.  
  2450.     /* I don't know if we should first send TELNET synch ? */
  2451.     net_rawout(buf, sizeof(buf));
  2452.     trace_str("SENT IP\n");
  2453. }
  2454.  
  2455. /*
  2456.  * net_abort
  2457.  *    Send telnet AO.
  2458.  *
  2459.  */
  2460. #if defined(X3270_TN3270E) /*[*/
  2461. void
  2462. net_abort(void)
  2463. {
  2464.     static unsigned char buf[] = { IAC, AO };
  2465.  
  2466.     if (e_funcs & E_OPT(TN3270E_FUNC_SYSREQ)) {
  2467.         /*
  2468.          * I'm not sure yet what to do here.  Should the host respond
  2469.          * to the AO by sending us SSCP-LU data (and putting us into
  2470.          * SSCP-LU mode), or should we put ourselves in it?
  2471.          * Time, and testers, will tell.
  2472.          */
  2473.         switch (tn3270e_submode) {
  2474.         case E_NONE:
  2475.         case E_NVT:
  2476.             break;
  2477.         case E_SSCP:
  2478.             net_rawout(buf, sizeof(buf));
  2479.             trace_str("SENT AO\n");
  2480.             if (tn3270e_bound ||
  2481.                 !(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE))) {
  2482.                 tn3270e_submode = E_3270;
  2483.                 check_in3270();
  2484.             }
  2485.             break;
  2486.         case E_3270:
  2487.             net_rawout(buf, sizeof(buf));
  2488.             trace_str("SENT AO\n");
  2489.             tn3270e_submode = E_SSCP;
  2490.             check_in3270();
  2491.             break;
  2492.         }
  2493.     }
  2494. }
  2495. #endif /*]*/
  2496.  
  2497. #if defined(X3270_ANSI) /*[*/
  2498. /*
  2499.  * parse_ctlchar
  2500.  *    Parse an stty control-character specification.
  2501.  *    A cheap, non-complaining implementation.
  2502.  */
  2503. static char
  2504. parse_ctlchar(char *s)
  2505. {
  2506.     if (!s || !*s)
  2507.         return 0;
  2508.     if ((int) strlen(s) > 1) {
  2509.         if (*s != '^')
  2510.             return 0;
  2511.         else if (*(s+1) == '?')
  2512.             return 0177;
  2513.         else
  2514.             return *(s+1) - '@';
  2515.     } else
  2516.         return *s;
  2517. }
  2518. #endif /*]*/
  2519.  
  2520. #if defined(X3270_MENUS) || defined(C3270) /*[*/
  2521. /*
  2522.  * net_linemode_chars
  2523.  *    Report line-mode characters.
  2524.  */
  2525. struct ctl_char *
  2526. net_linemode_chars(void)
  2527. {
  2528.     static struct ctl_char c[9];
  2529.  
  2530.     c[0].name = "intr";    (void) strcpy(c[0].value, ctl_see(vintr));
  2531.     c[1].name = "quit";    (void) strcpy(c[1].value, ctl_see(vquit));
  2532.     c[2].name = "erase";    (void) strcpy(c[2].value, ctl_see(verase));
  2533.     c[3].name = "kill";    (void) strcpy(c[3].value, ctl_see(vkill));
  2534.     c[4].name = "eof";    (void) strcpy(c[4].value, ctl_see(veof));
  2535.     c[5].name = "werase";    (void) strcpy(c[5].value, ctl_see(vwerase));
  2536.     c[6].name = "rprnt";    (void) strcpy(c[6].value, ctl_see(vrprnt));
  2537.     c[7].name = "lnext";    (void) strcpy(c[7].value, ctl_see(vlnext));
  2538.     c[8].name = 0;
  2539.  
  2540.     return c;
  2541. }
  2542. #endif /*]*/
  2543.  
  2544. #if defined(X3270_TRACE) /*[*/
  2545. /*
  2546.  * Construct a string to reproduce the current TELNET options.
  2547.  * Returns a Boolean indicating whether it is necessary.
  2548.  */
  2549. Boolean
  2550. net_snap_options(void)
  2551. {
  2552.     Boolean any = False;
  2553.     int i;
  2554.     static unsigned char ttype_str[] = {
  2555.         IAC, DO, TELOPT_TTYPE,
  2556.         IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
  2557.     };
  2558.  
  2559.     if (!CONNECTED)
  2560.         return False;
  2561.  
  2562.     obptr = obuf;
  2563.  
  2564.     /* Do TTYPE first. */
  2565.     if (myopts[TELOPT_TTYPE]) {
  2566.         unsigned j;
  2567.  
  2568.         space3270out(sizeof(ttype_str));
  2569.         for (j = 0; j < sizeof(ttype_str); j++)
  2570.             *obptr++ = ttype_str[j];
  2571.     }
  2572.  
  2573.     /* Do the other options. */
  2574.     for (i = 0; i < N_OPTS; i++) {
  2575.         space3270out(6);
  2576.         if (i == TELOPT_TTYPE)
  2577.             continue;
  2578.         if (hisopts[i]) {
  2579.             *obptr++ = IAC;
  2580.             *obptr++ = WILL;
  2581.             *obptr++ = (unsigned char)i;
  2582.             any = True;
  2583.         }
  2584.         if (myopts[i]) {
  2585.             *obptr++ = IAC;
  2586.             *obptr++ = DO;
  2587.             *obptr++ = (unsigned char)i;
  2588.             any = True;
  2589.         }
  2590.     }
  2591.  
  2592. #if defined(X3270_TN3270E) /*[*/
  2593.     /* If we're in TN3270E mode, snap the subnegotations as well. */
  2594.     if (myopts[TELOPT_TN3270E]) {
  2595.         any = True;
  2596.  
  2597.         space3270out(5 +
  2598.             ((connected_type != CN) ? strlen(connected_type) : 0) +
  2599.             ((connected_lu != CN) ? + strlen(connected_lu) : 0) +
  2600.             2);
  2601.         *obptr++ = IAC;
  2602.         *obptr++ = SB;
  2603.         *obptr++ = TELOPT_TN3270E;
  2604.         *obptr++ = TN3270E_OP_DEVICE_TYPE;
  2605.         *obptr++ = TN3270E_OP_IS;
  2606.         if (connected_type != CN) {
  2607.             (void) memcpy(obptr, connected_type,
  2608.                     strlen(connected_type));
  2609.             obptr += strlen(connected_type);
  2610.         }
  2611.         if (connected_lu != CN) {
  2612.             *obptr++ = TN3270E_OP_CONNECT;
  2613.             (void) memcpy(obptr, connected_lu,
  2614.                     strlen(connected_lu));
  2615.             obptr += strlen(connected_lu);
  2616.         }
  2617.         *obptr++ = IAC;
  2618.         *obptr++ = SE;
  2619.  
  2620.         space3270out(38);
  2621.         (void) memcpy(obptr, functions_req, 4);
  2622.         obptr += 4;
  2623.         *obptr++ = TN3270E_OP_IS;
  2624.         for (i = 0; i < 32; i++) {
  2625.             if (e_funcs & E_OPT(i))
  2626.                 *obptr++ = i;
  2627.         }
  2628.         *obptr++ = IAC;
  2629.         *obptr++ = SE;
  2630.  
  2631.         if (tn3270e_bound) {
  2632.             tn3270e_header *h;
  2633.  
  2634.             space3270out(EH_SIZE + 3);
  2635.             h = (tn3270e_header *)obptr;
  2636.             h->data_type = TN3270E_DT_BIND_IMAGE;
  2637.             h->request_flag = 0;
  2638.             h->response_flag = 0;
  2639.             h->seq_number[0] = 0;
  2640.             h->seq_number[1] = 0;
  2641.             obptr += EH_SIZE;
  2642.             *obptr++ = 1; /* dummy */
  2643.             *obptr++ = IAC;
  2644.             *obptr++ = EOR;
  2645.         }
  2646.     }
  2647. #endif /*]*/
  2648.     return any;
  2649. }
  2650. #endif /*]*/
  2651.  
  2652. /*
  2653.  * Set blocking/non-blocking mode on the socket.  On error, pops up an error
  2654.  * message, but does not close the socket.
  2655.  */
  2656. static int
  2657. non_blocking(Boolean on)
  2658. {
  2659. #ifdef AMIGA
  2660. {
  2661. long iOn=on?1:0;
  2662. int iRet;
  2663. iOn=1; /*prevent hanging*/
  2664. iRet=IoctlSocket(sock,FIONBIO,(char*)&iOn);
  2665. return(0);
  2666. }
  2667. #endif
  2668.  
  2669. #if !defined(BLOCKING_CONNECT_ONLY) /*[*/
  2670. # if defined(FIONBIO) /*[*/
  2671.     int i = on ? 1 : 0;
  2672.  
  2673.     if (ioctl(sock, FIONBIO, &i) < 0) {
  2674.         popup_an_errno(errno, "ioctl(FIONBIO)");
  2675.         return -1;
  2676.     }
  2677. # else /*][*/
  2678.     int f;
  2679.  
  2680.     if ((f = fcntl(sock, F_GETFL, 0)) == -1) {
  2681.         popup_an_errno(errno, "fcntl(F_GETFL)");
  2682.         return -1;
  2683.     }
  2684.     if (on)
  2685.         f |= O_NDELAY;
  2686.     else
  2687.         f &= ~O_NDELAY;
  2688.     if (fcntl(sock, F_SETFL, f) < 0) {
  2689.         popup_an_errno(errno, "fcntl(F_SETFL)");
  2690.         return -1;
  2691.     }
  2692. # endif /*]*/
  2693. #endif /*]*/
  2694.     return 0;
  2695. }
  2696.  
  2697. #if defined(X3270_TRACE) /*[*/
  2698.  
  2699. static void
  2700. trace_str(const char *s)
  2701. {
  2702.     if (!toggled(DS_TRACE))
  2703.         return;
  2704.     (void) fprintf(tracef, "%s", s);
  2705. }
  2706.  
  2707. static void
  2708. vtrace_str(const char *fmt, ...)
  2709. {
  2710.     static char trace_msg[256];
  2711.     va_list args;
  2712.  
  2713.     if (!toggled(DS_TRACE))
  2714.         return;
  2715.  
  2716.     va_start(args, fmt);
  2717.     (void) vsprintf(trace_msg, fmt, args);
  2718.     trace_str(trace_msg);
  2719. }
  2720.  
  2721. #endif /*]*/
  2722.